import logging
import time
import json
from datetime import datetime, timedelta
from django.conf import settings
from redis import StrictRedis
from common.utils import stringutils
from preprocessor.preprocessor import EventPreprocessor
from .model_router import ACCOUNT_MODEL_ROUTER, DEVICE_MODEL_ROUTER
from event_rule.dwc import NO_BET_AMOUNT_GAME_TYPE

_LOGGER = logging.getLogger(__name__)


class DWCEventPreprocessor(EventPreprocessor):
    """ DWC Preprocessor """

    def __init__(self, topic,
                 redis_conf_url=settings.CONSUMER_REDIS,
                 db_name='default',
                 add_prefix=True,
                 agent_redis_conf_url=settings.AGENT_CONSUMER_REDIS):
        super().__init__(topic, add_prefix)
        self.account_table = self.get_account_table()
        self.device_table = self.get_device_table()
        self.db_name = db_name
        self.redis = StrictRedis.from_url(redis_conf_url, charset="utf-8", decode_responses=True)
        self.agent_redis = StrictRedis.from_url(agent_redis_conf_url, charset="utf-8", decode_responses=True)

    def get_account_table(self):
        return ACCOUNT_MODEL_ROUTER[self.topic]

    def get_device_table(self):
        return DEVICE_MODEL_ROUTER[self.topic]

    def _get_key_by_ip_chn(self, ip, chn):
        return '{}:ip:{}:chn:{}'.format(self.topic, ip, chn)

    def _get_qk_key_by_ip_chn(self, ip, chn):
        return 'qk:{}:ip:{}:chn:{}'.format(self.topic, ip, chn)

    def get_key_by_agent_chn(self, ip):
        return 'agent_platform:{}:ip:{}'.format(self.topic, ip)

    def _qk_app_download_handler(self):
        app_id = stringutils.delete_no_ascii(self.event_data['_qk_appid']).strip()
        key = self._get_qk_key_by_ip_chn(self.event_data['_ip'], self.event_data['_chn'])
        self.redis.set(key, app_id)
        self.redis.expire(key, timedelta(hours=6))

    def _app_download_handler(self):
        app_id = stringutils.delete_no_ascii(self.event_data['_s2s_appid']).strip()
        key = self._get_key_by_ip_chn(self.event_data['_ip'], self.event_data['_chn'])
        self.redis.set(key, app_id)
        self.redis.expire(key, timedelta(hours=6))

    def _get_account_redis_key(self, user_id):
        return 'dwc:{}:account:{}'.format(self.topic, user_id)

    def get_account(self, user_id, get_object=False):
        system_default_user_id = 1
        if user_id == system_default_user_id:
            return
        if get_object:
            return self.account_table.objects.using(self.db_name).filter(user_id=user_id).first()
        account_redis_key = self._get_account_redis_key(user_id)
        account = self.redis.get(account_redis_key)
        if not account:
            account = self.account_table.objects.using(self.db_name).filter(user_id=user_id).first()
            if not account:
                return
            account = account.__dict__
            account.pop('_state')
            account['registered_at'] = str(account['registered_at'])
            account['active_at'] = str(account['active_at'])
            self.redis.set(account_redis_key, json.dumps(account))
            self.redis.expire(account_redis_key, timedelta(minutes=10))
        else:
            account = json.loads(account)
        account['registered_at'] = datetime.strptime(account['registered_at'], '%Y-%m-%d %H:%M:%S')
        account['active_at'] = datetime.strptime(account['active_at'], '%Y-%m-%d %H:%M:%S')
        return account

    def _register_handler(self):
        key = self._get_key_by_ip_chn(self.event_data['_ip'], self.event_data['_chn'])
        qk_key = self._get_qk_key_by_ip_chn(self.event_data['_ip'], self.event_data['_chn'])
        app_id, qk_app_id = self.redis.get(key), self.redis.get(qk_key),
        self.event_data['_s2s_appid'] = app_id
        self.event_data['_qk_appid'] = qk_app_id
        agent_chn_key = self.get_key_by_agent_chn(self.event_data['_ip'])
        agent_chn = self.agent_redis.get(agent_chn_key)
        self.event_data['_agent_chn'] = agent_chn
        event_datetime = datetime.fromtimestamp(self.event_data['_event_time'])
        account_information, created = self.account_table.objects.using(self.db_name).get_or_create(
            user_id=self.event_data['_user_id'],
            defaults={
                'user_id': self.event_data['_user_id'],
                'channel': self.event_data['_chn'],
                'ip': self.event_data['_ip'],
                'aid': self.event_data['_aid'],
                'device_type': self.event_data.get('_device_type', 0),
                'registered_at': event_datetime,
                'extra_info': app_id,
                'qk_appid': qk_app_id,
                'active_at': event_datetime,
                'agent_chn': agent_chn
            })
        if not created:
            _LOGGER.info('Account <{}> already exist'.format(self.event_data['_user_id']))

    def _tax_handler(self):
        if 'project_id' not in self.event_data:
            self.event_data['project_id'] = self.topic

    def _withdraw_handler(self):
        self.event_data['_withdraw_sub_type'] = self.event_data['sub_type']
        if self.event_data['_event_id'] == 'withdraw' and 'third_time' in self.event_data:
            self.event_data['third_time_interval'] = self.event_data['_event_time'] - self.event_data['third_time']
        if self.event_data['_event_id'] == 'withdraw_personal_check' and 'risk_check_time' in self.event_data:
            self.event_data['check_interval'] = self.event_data['_event_time'] - self.event_data['risk_check_time']

    def _bet_order_handler(self):
        unrestricted_room = {
            "dark4": [
                {"sub_type": "fish", "third_type": "1"},
                {"sub_type": "lord", "third_type": "0"},
            ],
            "dark3": [
                {"sub_type": "fish", "third_type": "1"},
                {"sub_type": "lord", "third_type": "0"},
            ]
        }
        self.event_data['no_limit_room'] = 0
        for room in unrestricted_room[self.topic]:
            if (self.event_data['sub_type'] == room['sub_type']
                    and self.event_data['third_type'] == room['third_type']):
                self.event_data['no_limit_room'] = 1
        self.event_data['third_type'] = '_'.join([self.event_data['sub_type'], self.event_data['third_type']])
        if self.event_data['sub_type'] in NO_BET_AMOUNT_GAME_TYPE and self.event_data['award_amount'] < 0:
            self.event_data['real_bet_amount'] = self.event_data['bet_amount'] - self.event_data['award_amount']
            self.event_data['real_award_amount'] = 0
        else:
            self.event_data['real_bet_amount'] = self.event_data['bet_amount']
            self.event_data['real_award_amount'] = self.event_data['award_amount']

    def _device_type_fix(self):
        if '_device_type' not in self.event_data:
            self.event_data['_device_type'] = 0

    def _get_or_create_device(self, aid, channel, ip, device_type, created_at, active_at):
        device, created = self.device_table.objects.using(self.db_name).get_or_create(
            aid=aid,
            defaults={
                'channel': channel,
                'ip': ip,
                'aid': aid,
                'device_type': device_type,
                'created_at': created_at,
                'active_at': active_at
            })
        return device, created

    def _get_device_redis_key(self, aid):
        return '{}:device:{}'.format(self.topic, aid)

    def _active_handler(self):
        active_time = datetime.fromtimestamp(self.event_data['_event_time'])
        device_redis_key = self._get_device_redis_key(self.event_data['_aid'])
        device = self.redis.get(device_redis_key)
        if not device:
            _, _ = self._get_or_create_device(self.event_data['_aid'], self.event_data['_chn'],
                                              self.event_data['_ip'], self.event_data['_device_type'],
                                              active_time, active_time)

    def get_device(self, aid, get_object=False):
        if get_object:
            return self.device_table.objects.using(self.db_name).filter(aid=aid).first()
        device_redis_key = self._get_device_redis_key(aid)
        device = self.redis.get(device_redis_key)
        if not device:
            device = self.device_table.objects.using(self.db_name).filter(aid=aid).first()
            if not device:
                return
            device = device.__dict__
            device.pop('_state')
            device['created_at'] = datetime.strftime(device['created_at'], '%Y-%m-%d %H:%M:%S')
            device['active_at'] = datetime.strftime(device['active_at'], '%Y-%m-%d %H:%M:%S')
            self.redis.set(device_redis_key, json.dumps(device))
            self.redis.expire(device_redis_key, timedelta(hours=2))
        else:
            device = json.loads(device)
        device['created_at'] = datetime.strptime(device['created_at'], '%Y-%m-%d %H:%M:%S')
        device['active_at'] = datetime.strptime(device['active_at'], '%Y-%m-%d %H:%M:%S')
        return device

    @staticmethod
    def event_ids_for_not_process():
        return ['app_download', 'agent_bind_chn', 'register', 'qk_app_download']

    def user_event_process(self):
        if self.event_data['_event_id'] in self.event_ids_for_not_process():
            return
        event_datetime = datetime.fromtimestamp(self.event_data['_event_time'])
        event_date = event_datetime.replace(hour=0, minute=0, second=0, microsecond=0)
        user_id = self.event_data.get('_user_id')
        account = self.get_account(user_id=user_id) if user_id else None
        if account:
            self.event_data['_chn'] = account['channel']
            self.event_data['_s2s_appid'] = account['extra_info']
            self.event_data['_registered_at'] = int(time.mktime(account['registered_at'].timetuple()))
            register_date = account['registered_at'].replace(hour=0, minute=0, second=0, microsecond=0)
            self.event_data['_active_days'] = (event_date - register_date).days
            self.event_data['_is_new_user'] = 1 if event_date == register_date else 0
            self.event_data['_aid'] = account['aid']
            self.event_data['_device_type'] = account['device_type']
            self.event_data['_agent_chn'] = account.get('agent_chn')
            self.event_data['_qk_appid'] = account.get('qk_appid')
            aid = account['aid']
        else:
            aid = self.event_data.get('_aid')
        if aid:
            device = self.get_device(aid)
            if device:
                device_created_date = device['created_at'].replace(hour=0, minute=0, second=0, microsecond=0)
                self.event_data['_device_created_at'] = int(time.mktime(device['created_at'].timetuple()))
                self.event_data['_device_active_days'] = (event_date - device_created_date).days
                self.event_data['_is_new_device'] = 1 if event_date == device_created_date else 0

    def handle(self, event_data):
        self.event_data = event_data.copy()
        event_id = self.event_data['_event_id']
        if event_id in ['register', 'bind', 'active']:
            self._device_type_fix()
        if event_id == 'app_download':
            self._app_download_handler()
        if event_id == 'qk_app_download':
            self._qk_app_download_handler()
        if event_id == 'register':
            self._register_handler()
        if event_id == 'active':
            self._active_handler()
        if event_id == 'tax':
            self._tax_handler()
        if event_id == 'bet_order':
            self._bet_order_handler()
        if 'withdraw' in event_id:
            self._withdraw_handler()
        self.add_event_prefix()
        self.user_event_process()
        if self.event_data.get('_chn'):
            self.event_data['_chn_device_type'] = "ios" if self.event_data['_chn'].startswith("ios_") else "android"
        return self.event_data
